// $Id: distributionsgnutella.cpp 74 2005-05-15 19:54:19Z hansemil $
#include "distributionsgnutella.h"
#include "clock.h"

#include <math.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

/**
 * The constructor sets the instance of the singelton class to this object, except for if the leaveInstance variable is set to true
 * @param leaveInstance If set to false (default), a call to distributions.getInstance() will return a pointer to this object. If set to true, the getInstance-call will be unaffected.
 */
DistributionsGnutella::DistributionsGnutella(bool leaveInstance)
	: Distributions(leaveInstance)
{
}

/**
 * @todo Write docs
 * @todo Specify where this distribution comes from (simulators.txt)
 *
 * @param value ...
 * @returns ...
 */
unsigned int DistributionsGnutella::bandwidthDown(unsigned int value)
{
	double x = value/(RAND_MAX/100.0);
	unsigned int retval;

	if(x < 9){
		retval = (unsigned int) ((6.6005 * x) + 15.397);
	}
	else if(x < 69){
		retval = (unsigned int) ((-0.0452*::pow(x,2)) + 51.401*x - 315.07);
	}
	else if(x < 97){
		retval = (unsigned int) (1.0035*::exp(0.1167*x));
	}
	else{
		retval = (unsigned int) ((1*::pow(10,-42))*::exp(1.1036*x));
	}

	return ((retval/8)*Clock::m_secondsPerTimeStep)*1024;
}

/**
 * @todo Write docs
 * @todo Specify where this distribution comes from (simulators.txt)
 *
 * @param value ...
 * @returns ...
 */
unsigned int DistributionsGnutella::bandwidthUp(unsigned int value)
{
	double x = value/(RAND_MAX/100.0);
	unsigned int retval;

	if(x < 23){
		/// @todo Maybe match the first curves in up and down speed..?
		retval = (unsigned int) (3.973*x + 23.548);
	}
	else if(x < 46){
		retval = (unsigned int) (18.351*::exp(0.0776*x));
	}
	else if(x < 70){
		retval = (unsigned int) (202.99*::exp(0.0253*x));
	}
	else if(x < 77){
		retval = (unsigned int) (0.0015*::exp(0.1946*x));
	}
	else if(x < 94){
		retval = (unsigned int) (0.0194*::pow(x,2.8539));
	}
	else{
		retval = (unsigned int) ((3*::pow(10,-24))*::exp(0.6738*x));
	}

	return ((retval/8)*Clock::m_secondsPerTimeStep)*1024;
}

/**
 * @todo Write docs
 * @todo Specify where this distribution comes from (simulators.txt)
 *
 * @param value ...
 * @returns ...
 */
unsigned int DistributionsGnutella::filePopularity(unsigned int value)
{
	double x = value/(RAND_MAX/100.0);

	if(x < 1){
		///@todo Values between zero and one should use a linear distribution
		return 0;
	}
	//else if(x < 66){
	else if(x < 65){
		return (unsigned int) ((20.457*::log(x) + 10.999)*(RAND_MAX/100.0));
	}
	else{
		return (unsigned int) ((0.1013*x + 89.86)*(RAND_MAX/100.0));
	}
}

/**
 * @todo Write docs
 * @todo Specify where this distribution comes from (simulators.txt)
 *
 * @param value ...
 * @returns ...
 */
unsigned int DistributionsGnutella::fileSize(unsigned int value)
{
	double x = value/(RAND_MAX/4584.0);

	if(x < 1800){
		return (unsigned int) (0.017*::pow(x,2.1099));
	}
	else if(x < 4310){
		return (unsigned int) (4456.1*x - 8*::pow(10,6));
	}
	else{
		return (unsigned int) (8*::pow(10,-24)*::exp(0.0161*x));
	}
}
